package com.cxm.report.service.impl;

import com.cxm.report.dao.ChannelReportDao;
import com.cxm.report.model.IReport;
import com.cxm.report.model.criteria.ReportFilter;
import com.cxm.report.model.data.BrandReport;
import com.cxm.report.model.data.ChannelReport;
import com.cxm.report.model.data.Report;
import com.cxm.report.model.data.ReportDetail;
import com.cxm.report.model.event.MailEvent;
import com.cxm.report.service.ChannelReportService;
import com.cxm.report.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author scl.BlueOcean
 * @version 1.0
 * @date 2018年07月02 18:14
 * @description
 */
@Service
public class ChannelReportServiceImpl extends AbstractReportService implements ChannelReportService {
    @Autowired
    private ChannelReportDao reportDao;
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void report(String start, String end) {
        Date now = new Date();
        //如果开始时间大于当前时间，报错
        if (DateUtil.compare(start,now) > 0){
            throw new RuntimeException("不支持的时间范围");
        }
        //如果结束时间大于当前时间，将结束时间设置成当前时间
        if (DateUtil.compare(end,now) > 0){
            end = DateUtil.detaultFormat(now);
        }

        //查询结束时间是否有数据
        int count = reportDao.count(end);
        if (count <= 0 ){
            //如果没数据，刷新数据
            refreshData(end);
        }
        //生成报告
        generateReport(start,end);
    }
    /**
     * 刷新数据
     * @param date
     */
    @Override
    public void refreshData(String date) {
        reportDao.delete(date);
        reportDao.insertChannelInfo(date);
        reportDao.updateBackInfo(date);
        reportDao.updateSuccessInfo(date);
        reportDao.updateFailedNum(date);
        reportDao.updateOverTimeNum(date);
        reportDao.updateNoRecordNum(date);
        reportDao.updateInquiryNum(date);
    }

    @Override
    public List<ChannelReport> getReports(ReportFilter filter) {
        return  reportDao.selectReport(filter.getBegin(),filter.getEnd());
    }

    @Override
    public List<Report> timeScopeReport(ReportFilter filter) {
        List<Report> reports = new ArrayList<>();
        List<ChannelReport> reportList = reportDao.selectReportsOfScope(filter);
        generateReport(reports,String.format("%s～%s",filter.getBegin(),filter.getEnd()),reportList);
        return reports;
    }

    @Override
    public List<Report> dayReport(ReportFilter filter) {
        List<ChannelReport> reportList = reportDao.selectReports(filter);
        return getReports(reportList,null);
    }

    @Override
    public List<Report> monthReport(ReportFilter filter) {
        Report lastReport = getLastReport(filter.getBegin(),IReport.ScopeType.MONTH);
        List<ChannelReport> reportList = reportDao.selectReportsGroupMonth(filter);
        List<Report> reports = getReports(reportList, lastReport);
        Collections.reverse(reports);
        return reports;
    }


    @Async
    void generateReport(String start, String end) {
        ReportFilter filter = new ReportFilter();
        filter.setBegin(start);
        filter.setEnd(end);
        Report report = weekReport(filter).get(0);
        applicationContext.publishEvent(new MailEvent(report));
    }
    @Override
    public List<Report> weekReport(ReportFilter filter) {
        Report lastReport = getLastReport(filter.getBegin(),IReport.ScopeType.WEEK);
        List<ChannelReport> reportList = reportDao.getReportGroupByWeek(filter);
        List<Report> reports = getReports(reportList,lastReport);
        Collections.reverse(reports);
        setFirstAndLast(reports,filter);
        return reports;
    }

    /**
     * 生成上期报告
     * @param scopeType
     * @return
     */
    private Report getLastReport(String date, String scopeType) {
        try {
            ReportFilter filter = new ReportFilter();
            switch (scopeType){
                case IReport.ScopeType.MONTH:{
                    String[] monthScope = DateUtil.getLastMonthScope(date);
                    filter.setBegin(monthScope[0]);
                    filter.setEnd(monthScope[1]);
                    List<ChannelReport>  reportList = reportDao.selectReportsGroupMonth(filter);
                    List<Report> reports = getReports(reportList, null);
                    return reports.get(0);
                }
                case IReport.ScopeType.WEEK:{
                    date = date.split("To")[0].trim();
                    String[] weekScope = DateUtil.getLastWeekScope(date);
                    filter.setBegin(weekScope[0]);
                    filter.setEnd(weekScope[1]);
                    List<ChannelReport>  reportList = reportDao.getReportGroupByWeek(filter);
                    List<Report> reports = getReports(reportList, null);
                    return reports.get(0);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private List<Report> getReports(List<ChannelReport> reportList,Report lastReport) {
        List<Report> reports = new ArrayList<>();
        Map<String, List<ChannelReport>> reportGroup = reportList.stream().collect(Collectors.groupingBy(ChannelReport::getReportDate,
                LinkedHashMap::new, Collectors.toList()));
        for (Map.Entry<String, List<ChannelReport>> reportMap : reportGroup.entrySet()) {
            Report report =  generateReport(reports, reportMap.getKey(),reportMap.getValue());
            setRingRatio(lastReport,report);
            lastReport = report;
        }
        return reports;
    }
    /**
     * 设置环比
     * @param lastReport
     * @param report
     */
    private void setRingRatio(Report lastReport,Report report){
        //如果期的报告为null，需要生成上期报告
        if (lastReport != null){
            List<ChannelReport> lastReports = (List<ChannelReport>) lastReport.getDetails();
            Map<String, ChannelReport> reportMap = lastReports.stream().collect(Collectors.toMap(ChannelReport::getChannelName, b->b,(k1, k2)->k1));

            List<ChannelReport> reports = (List<ChannelReport>) report.getDetails();
            for (ChannelReport rep : reports) {
                ChannelReport br = reportMap.get(rep.getChannelName());
                if (br != null){
                    setRingRatio(rep,br);
                }
            }
            setRingRatio((ReportDetail) report.getTotal(),(ReportDetail)lastReport.getTotal());
        }
    }
    private Report generateReport(List<Report> reports, String date,List<ChannelReport> details) {
        Report report = new Report();
        report.setType(IReport.Type.CHANNEL);
        report.setDate(date);
        report.setDetails(details);
        //计算合计
        report.setTotal(caculateTotal(details));
        reports.add(report);
        return report;
    }

    /**
     * 计算合计
     * @param details
     * @return
     */
    private ChannelReport caculateTotal(List<ChannelReport> details) {
        ChannelReport total = details.stream().reduce(new ChannelReport(),(x,y)->{
            x.setOrderNum(x.getOrderNum()+y.getOrderNum());
            x.setBackNum(x.getBackNum()+y.getBackNum());
            x.setSuccessNum(x.getSuccessNum()+y.getSuccessNum());
            x.setAvgSuccessTime(x.getAvgSuccessTime()+y.getSuccessNum()*y.getAvgSuccessTime());
            x.setFailedNum(x.getFailedNum()+y.getFailedNum());
            x.setOverTimeNum(x.getOverTimeNum()+y.getOverTimeNum());
            x.setInquiryNum(x.getInquiryNum()+y.getInquiryNum());
            x.setNoRecordNum(x.getNoRecordNum()+y.getNoRecordNum());
            return x;
        });
        total.setAvgSuccessTime(total.getAvgSuccessTime()/total.getSuccessNum());
        return total;
    }
}
